//
//  LGSName.h
//  LogicSim
//
//  Created by Jeremy Pereira on 26/02/2013.
//
//

#import <Foundation/Foundation.h>

enum
{
    /*!
     *  @brief This value indicates the index part of a name (either node or
     *  connection) does not exist.
     */
    LGS_NAME_NO_INDEX = -1,
    /*!
     *  @brief Index used as a placeholder when adding new nodes.
     *
     *  This allows us to add the object and have a generic reindexing method.
     */
    LGS_NAME_PLACEHOLDER_INDEX = INT_MAX,
};

/*!
 *  @brief Name object for nodes and connections.
 *
 *  A name is a structured string consisting of a node and a connection.
 *  When represented as a string, they are separated by a dot.  Either the node 
 *  part or the connection part can be nil meaning there isn't one. i.e. nodes 
 *  are specified by an LGSName with just a node part.
 *  The node and the connection can also have an index associated with it.
 *  This class is immutable.
 */
@interface LGSName : NSObject <NSCopying>

/*!
 *  @brief Designated initialiser
 *  @param nodePart node part of this name.
 *  @param connectionPart Connection part of this name or nil if it represents 
 *  a node.
 *  @param nodeIndex The node index of this name if we have multiple nodes with
 *  the same name.
 *  @param connectionIndex The connection index of this name if the node has 
 *  multiple connections of the same name.
 *  @return A new LGSName.
 */
-(id) initWithNodePart: (NSString*) nodePart
		connectionPart: (NSString*) connectionPart
			 nodeIndex: (int) nodeIndex
       connectionIndex: (int) connectionIndex;

/*!
 *  @brief Give us a new instance of an LGSName.
 *  @param aString String to parse to get the node and connection
 *  @return an LGSName.
 */
+(LGSName*) nameWithString: (NSString*) aString;

/*!
 *  @brief Construct a name with just a connection string.
 *
 *  @param aString String to name the connection part with.
 *  @return A name with a nil node and a connection of aString, parsed for an
 *  index.
 */
+(LGSName*) nameWithConnectionString: (NSString*) aString;

/*!
 *  @brief The node part of the name
 */
@property (nonatomic, readonly, copy) NSString* nodePart;
/*!
 *  @brief The connection part of the name
 */
@property (nonatomic, readonly, copy) NSString* connectionPart;

/*!
 *  @brief Return the name as a dotted string
 */
@property (nonatomic, readonly, copy) NSString* stringValue;

/*!
 *  @brief The node index of this name or LGS_NAME_NO_INDEX
 */
@property (readonly, assign) int nodeIndex;
/*!
 *  @brief The connection index of this name or LGS_NAME_NO_INDEX
 */
@property (readonly, assign) int connectionIndex;

/*!
 *  @brief This name but without a connection part
 */
@property (nonatomic, readonly, copy) LGSName* nameWithoutConnection;
/*!
 *  @brief This name but without a node part
 */
@property (nonatomic, readonly, copy) LGSName* nameWithoutNode;

/*!
 *  @brief This name but with no node index
 */
@property (nonatomic, readonly, copy) LGSName* nameWithoutNodeIndex;

/*!
 *  @brief return a new name with the same node part and a new connection part.
 *  @param connection Connection name string.
 *  @return A new name but with the given connection.
 */
-(LGSName*) nameWithConnectionString: (NSString*) connection;
/*!
 *  @brief return a new name with the same node part and a new connection part.
 *  @param connection Connection name.  If it has a node part it will be ignored.
 *  @return A new name but with the given connection.
 */
-(LGSName*) nameWithConnection: (LGSName*) connection;

/*!
 *  @brief This name but with a node index added.
 *  @param nodeIndex The node index for the new name.
 *  @return A new name with the given node index.
 */
-(LGSName*) nameWithNodeIndex: (int) nodeIndex;

/*!
 *  @brief This name but with a connection index added.
 *  @param connectionIndex The connection index for the new name.
 *  @return A new name with the given connection index.
 */
-(LGSName*) nameWithConnectionIndex: (int) connectionIndex;

/*!
 *  @brief Do a comparison with another name lexically according to the 
 *  current locale.
 *  @param other Other name to compare with.
 *  @return NSOrderedAscending, NSOrderedSame, NSOrderedDescending according to
 *  the ordering.
 */
-(NSComparisonResult) localizedCompare: (LGSName*) other;

#pragma mark Common constants
/*!
 *  @brief a null name
 *  @return The null name
 */
+(LGSName*) null;

@end

/*!
 *  @brief Convenience string manipulation methods for nodes.
 */
@interface NSString (LGSName)

/*!
 *  @brief Split a string into a node name and a connection name.
 *
 *  Nodes and connections can be represented as node.connection e.g. aAndB.a.
 *  This method returns a two element array with the node and the connection -
 *  or nil if it can't be split.
 *  @return The string split into a node and a connction.
 */
-(NSArray*) splitIntoNodeAndConnection;

/*!
 *  @brief Convert this string to an LGSName.
 *
 *  @return The string as an LGSName
 */
-(LGSName*) asName;

/*!
 *  @brief Convert the string into a connection name.
 *
 *  @return An LGSName with a nil node part.
 */
-(LGSName*) asConnectionName;

@end

